#include <memory>
#include <sys/epoll.h>
#include <wait.h>
#include <functional>
#include <sys/select.h>
#include "Common.hpp"
#include "Socket.hpp"
#define FDSIZE 1024
#define MAXEVENTS 128
int const fd_default = -1;
using namespace SocketMoudule;
using ioservice_t = function<void(shared_ptr<Socket> &, InetAddr &)>;
class TcpServer
{
public:
    TcpServer()
    {
        // 完成初始化（创建套接字、绑定端口、开启监听）...
        //......

        // 创建epoll模型
        _epfd = epoll_create(0);

        // 组织一个epoll_event变量，设置文件描述符和要关心的事件
        epoll_event event;
        event.data.fd = _listenfd;
        event.events = EPOLLIN;

        // 将该文件信息设置到内核里
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenfd, &event);
    }
    // 处理普通fd获取
    void SolveAccept()
    {
        InetAddr client;
        auto sock = _listensockptr->Accept(&client);
        epoll_event event;
        event.data.fd = sock->Fd();
        event.events = EPOLLIN;
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sock->Fd(), &event);
        if (n < 0)
            LOG(Level::WARING) << "accept epoll_ctl fail";
        else
            LOG(Level::INFO) << "accept epoll_ctl success";
    }
    // 处理读数据
    void SolveRead(int fd)
    {
        char buffer[1024];
        int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
        if (n == 0)
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            close(fd);
            cout << "client " << fd << " out..." << endl;
        }
        else if (n < 0)
        {
            epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
            close(fd);
            cout << "client " << fd << "recv fail" << endl;
        }
        else
        {
            buffer[n] = '\0';
            cout << "client say@: " << buffer << endl;
        }
    }
    void Start(ioservice_t callout)
    {
        _isrunning = true;
        while (_isrunning)
        {
            int tm = 1000;
            int n = epoll_wait(_epfd, _events, MAXEVENTS, tm);
            // 函数执行错误
            if (n < 0)
            {
                LOG(Level::WARING) << "epoll_wait fail\n";
            }
            // 超时
            else if (n == 0)
            {
                cout << "overtime..." << endl;
            }
            // 事件派发
            else
            {
                for (int i = 0; i < n; i++)
                {
                    if (_events[i].events | EPOLLIN)
                    {
                        if (_events[i].data.fd == _listensockptr->Fd())
                            SolveAccept();
                        else
                            SolveRead(_events[i].data.fd);
                    }
                }
            }
        }
    }

private:
    int _listenfd;
    int _epfd;
    struct epoll_event _events[MAXEVENTS];
    // 其他成员......
};

void HandlerEvent(int n)
{
    for (int i = 0; i < n; i++)
    {
        // 处理读事件就绪
        if (_events[i].events | EPOLLIN)
        {
            //_listenfd文件就绪
            if (_events[i].data.fd == _listenfd)
                SolveAccept();
            // 普通文件就绪
            else
                SolveRead(_events[i].data.fd);
        }
        // 处理其他事件就绪......
        //  else if(){}
    }
}
void Start(ioservice_t callout)
{
    _isrunning = true;
    while (_isrunning)
    {
        int tm = 1000; // 阻塞等待1000毫秒
        int n = epoll_wait(_epfd, _events, MAXEVENTS, tm);
        // 函数执行错误
        if (n < 0)
        {
            std::cout << "epoll_wait fail\n"
                      << std::endl;
            exit(1);
        }
        // 超时处理
        else if (n == 0)
        {
            std::cout << "overtime..." << std::endl;
        }
        // 事件派发
        else
        {
            std::cout << "事件就绪..." << std::endl;
            HandlerEvent(n);
        }
    }
}


// 处理读数据
void SolveRead(int userfd)
{
    char buffer[1024];
    int n = recv(userfd, buffer, sizeof(buffer) - 1, 0);
    if (n <= 0)
    {
        //recv返回值为0，用户断开连接；recv返回值为小于0，读取异常。
        //这两种情况需要将userfd从内核中移除再关闭该文件。
        epoll_ctl(_epfd, EPOLL_CTL_DEL, userfd, nullptr);
        close(userfd);
    }
    else
    {
        buffer[n] = '\0';
        cout << "client say@: " << buffer << endl;
    }
}